package olegroshka.src.com.bofa.olegroshka.datasource;

import java.text.ParseException;
import java.util.Iterator;

import olegroshka.src.com.bofa.olegroshka.filter.Filter;
import olegroshka.src.com.bofa.olegroshka.parsers.Parser;

public class MappingDataSource implements DataSource<Object[]> {

	@SuppressWarnings("rawtypes")
	private static final Filter[] NULL_FILTERS = new Filter[] {null, null, null};
	
	private final Parser<?>[] parsers;
	private final Filter<Object>[] filters;
	private final DataSource<String[]> textDataSource;	


	public MappingDataSource(
			DataSource<String[]> textDataSource,
			Parser<?>[] parsers, 
			Filter<Object>[] filters) {
		super();
		this.textDataSource = textDataSource;
		this.parsers = parsers;
		this.filters = filters;
	}
	
	@SuppressWarnings("unchecked")
	public MappingDataSource(
			DataSource<String[]> textDataSource,
			Parser<?>[] parsers) {
		super();
		this.textDataSource = textDataSource;
		this.parsers = parsers;
		this.filters = NULL_FILTERS;
	}

	public Iterator<Object[]> iterator() {
		final Iterator<String[]> textDataIterator = textDataSource.iterator();
		
		return new Iterator<Object[]>() {

			private Object[] current = null;
			public boolean hasNext() {
				if( current == null ) {
					current = next();
				}
				return current != null;
			}

			public Object[] next() {
				Object[] row = current;
				if( row != null ) {
					current = null;
				}

				while ( row == null && textDataIterator.hasNext() ) {
					String[] textValues = textDataIterator.next();
					row = new Object[textValues.length];
					for (int i = 0; i < textValues.length; i++) {
						try {
							row[i] = parsers[i].parse(textValues[i]);
						} catch (ParseException e) {
							throw new IllegalStateException("Can't parse " + textValues[i] + 
									", parser: " + parsers[i], e);
						}
						
					}
					if( filters != null && filters.length > 0 ) {
						for (int i = 0; i < filters.length; i++) {
							Filter<Object> filter = filters[i];
							if ( filter != null && !filter.accept(row[i]) ) {
								row = null;
								break;
							} 
						}
					}
				}
				return row;
			}

			public void remove() {
				throw new UnsupportedOperationException();
			}
		};
	}

	public void begin() {
		textDataSource.begin();
	}

	public void end() {
		textDataSource.end();
	}

}
